home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
001-025
/
scopedisk14
/
hamklido
/
hamkaleid.c
next >
Wrap
C/C++ Source or Header
|
1995-03-18
|
9KB
|
297 lines
/* ______________________
/
/ Kaleidoscope ____________________
______________________/ by /
Greg Searle /
______________________/
Creates a pretty, moving pattern on a lowres HAM screen. Colors change
smoothly as the pattern is drawn, randomly moving through all 4096 colors.
This program uses the famous "bouncing ball" to guide the pattern. A moving
point follows a straight line until it hits the edge of the screen, where it
"bounces off" somewhat randomly.
This program multitasks fine. The program is active only once per screen
refresh (60 times per second), leaving plenty of time for other programs. The
regular screen gadgets (dragbar, close box, layering gadgets) are hidden under
the pattern. Just hit the close box at the upper-right to shut down the
program.
*/
#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;
struct BitMap *bmap;
struct RastPort *rp;
struct ViewPort *vp;
struct Screen *scr;
struct Window *win;
struct NewScreen screen = {
0, 0, 0, 0, 0, /* LeftEdge, TopEdge, Width, Height, Depth */
-1, -1, /* DetailPen, BlockPen (default) */
0, CUSTOMSCREEN, /* ViewModes, Type */
NULL, NULL, /* *Font (default), *DefaultTitle */
NULL, NULL /* *Gadgets, *CustomBitMap */
};
#define WFLAGS WINDOWCLOSE | SIMPLE_REFRESH | ACTIVATE | \
BORDERLESS | BACKDROP | RMBTRAP
#define WIDCMP CLOSEWINDOW
struct NewWindow window = { /* This will only create a close box */
0, 0, 13, 10, /* LeftEdge, TopEdge, Width, Height */
-1, -1, /* DetailPen, BlockPen (default) */
WIDCMP, /* IDCMPFlags */
WFLAGS, /* Flags */
NULL, NULL, /* *FirstGadget, *CheckMark */
NULL, NULL, NULL, /* *Title, *Screen (to be set), *BitMap */
0, 0, 0, 0, /* MinWidth, MinHeight, MaxWidth, MaxHeight */
CUSTOMSCREEN /* Type */
};
#define WIDTH 320
#define HEIGHT 200
#define DEPTH 6
#define LENGTH 60
#define LINES 3
short fromCLI = 0;
main (argv, argc)
char *argv[];
long argc;
{
short error;
long x[LINES], dx[LINES], xx, yy, i, j, k, l, cc = 0;
float y[LINES], dy[LINES], p[3][LINES], dp[3][LINES];
struct IntuiMessage *message, *GetMsg();
fromCLI = argc;
if (error = OpenLibraries()) GoAway(error);
if (error = CreateScreen("Screen", WIDTH, HEIGHT, DEPTH, (short)HAM))
GoAway(error);
ShowTitle(scr, FALSE);
SetRGB4 (vp, 0L, 0L, 0L, 0L);
SetRast (rp, 0L);
SetDrMd (rp, JAM1);
rnd ((short) -VBeamPos()); /* Init random number generator */
for (l = 0; l < LINES; l++) {
x[l] = rnd (WIDTH);
y[l] = rnd (HEIGHT);
dx[l] = rnd(1) * 2 - 1; /* x changes only by one, */
do /* keeping pattern smooth */
dy[l] = (float)(rnd(23) - 11) / 6;
while (dy[l] == 0);
/* Init colors */
for (i = 0; i < 3; i++) { /* Uses "bouncing ball" technique to */
p[i][l] = rnd(15); /* change colors smoothly, yet randomly */
do
dp[i][l] = (float)(rnd(21) - 10) / 3;
while (dp[i][l] == 0.0);
}
}
/********** MAIN LOOP **********/
while (!GetMsg(win -> UserPort)) {
/* Set current color, then increment colors for each line. */
/* R, G, and B are controlled by "bouncing" vectors. */
/* Once they reach their limit, they reverse at a random speed. */
WaitTOF(); /* Delay - save multitasking */
if (++cc > 2) cc = 0;
for (l = 0; l < LINES; l++) {
SetAPen (rp, cc * 16L + 16L + (long) p[cc][l]);
if (!cc) {
for (i = 0; i < 3; i++) {
if ((p[i][l] += dp[i][l]) > 15 || p[i][l] < 0) {
if (p[i][l] > 15.0)
p[i][l] = 30.0 - p[i][l];
else
p[i][l] = -p[i][l];
do
dp[i][l] = ((p[i][l] < 8) ? 1 : -1) * (float)(rnd(10) + 1) / 3;
while (dp[i][l] == 0.0);
}
}
}
/* Draw: first x,y & mirrors, then y,x & mirrors. */
/* i & j are y and x converted into x and y, respectively. */
/* This allows use of the full screen, instead of just a square. */
i = (long)(y[l] / (float)HEIGHT * (float)WIDTH);
j = (long)((float)x[l] / (float)WIDTH * (float)HEIGHT);
xx = WIDTH - x[l];
yy = HEIGHT - (long)y[l];
Line (rp, x[l], (long)y[l]-LENGTH/2, x[l], (long)y[l]+LENGTH/2);
Line (rp, xx, (long)y[l]-LENGTH/2, xx, (long)y[l]+LENGTH/2);
Line (rp, x[l], yy-LENGTH/2, x[l], yy+LENGTH/2);
Line (rp, xx, yy-LENGTH/2, xx, yy+LENGTH/2);
xx = WIDTH - i;
yy = HEIGHT - j;
for (k = 0; k < 3; k++) {
SetDrPt (rp, 0x92492492 >> k);
SetAPen (rp, k * 16L + 16L + (long) p[k][l]);
Line (rp, i-LENGTH/2, j, i+LENGTH/2, j);
Line (rp, xx-LENGTH/2, j, xx+LENGTH/2, j);
Line (rp, i-LENGTH/2, yy, i+LENGTH/2, yy);
Line (rp, xx-LENGTH/2, yy, xx+LENGTH/2, yy);
}
SetDrPt (rp, 0xFFFFFFFF);
/* Increment x,y. Check if bounced off edge. */
if ((x[l] += dx[l]) < 0 || x[l] > WIDTH) {
x[l] -= dx[l];
dx[l] = -dx[l];
}
if ((y[l] += dy[l]) < 0 || y[l] > (float)HEIGHT) {
y[l] -= dy[l];
dy[l] = -dy[l];
do
dy[l] = ((dy[l]<0) ? -1:1) * (float)(rnd(23) - 11) / 6;
while (dy[l] == 0);
}
} /* for l */
} /* while */
GoAway(0);
} /* main */
Line (rp, x1, y1, x2, y2) /* Just draws a line and checks for edges */
struct RastPort *rp;
long x1, y1, x2, y2;
{
if (x1 < 0) x1 = 0;
else if (x1 > WIDTH-1) x1 = WIDTH-1;
if (y1 < 0) y1 = 0;
else if (y1 > HEIGHT-1) y1 = HEIGHT-1;
if (x2 < 0) x2 = 0;
else if (x2 > WIDTH-1) x2 = WIDTH-1;
if (y2 < 0) y2 = 0;
else if (y2 > HEIGHT-1) y2 = HEIGHT-1;
Move (rp, x1, y1);
Draw (rp, x2, y2);
}
short OpenLibraries()
{
void *OpenLibrary();
if (!(IntuitionBase = (struct IntuitionBase *)
OpenLibrary ("intuition.library", 1L))) return 1;
if (!(GfxBase = (struct GfxBase *)
OpenLibrary ("graphics.library", 1L))) return 2;
return 0;
} /* OpenLibraries */
short CreateScreen (title, width, height, depth, modes)
char title[];
short width, height, depth, modes;
{
struct Screen *OpenScreen();
struct Window *OpenWindow();
screen.Width = width;
screen.Height = height;
screen.Depth = depth;
screen.ViewModes = modes | ((width > 320) ? HIRES:0)
| ((height > 200) ? LACE:0);
if (!(scr = OpenScreen (&screen))) return 3;
window.Screen = scr;
if (!(win = OpenWindow (&window))) return 4;
vp = &(scr -> ViewPort);
rp = &(scr -> RastPort);
return 0;
} /* CreateScreen */
GoAway(error)
short error;
{
Report (error);
if (IntuitionBase) CloseLibrary (IntuitionBase);
if (GfxBase) CloseLibrary (GfxBase);
if (win) CloseWindow (win);
if (scr) CloseScreen (scr);
exit (0L);
} /* GoAway */
Report (error)
short error;
{
if (!error) return;
if (!fromCLI)
DisplayBeep(NULL);
else
switch (error) {
case 1: printf("Can't open Intuition.\n"); break;
case 2: printf("Can't open Graphics.\n"); break;
case 3: printf("Can't open Screen.\n"); break;
case 4: printf("Can't open Window.\n"); break;
default: printf("Undefined error.\n"); break;
} /* switch */
} /* Report */
#asm
*\
* :ts=8
* Yet Another random number generator. By Leo Schwab.
* Based on an idea posted on the USENET (Thanks, Sam Dicker!)
* For the Manx assembler.
*
* Calling convention:
* short rnd (range);
* short range;
*
* 8606.30
*/
public _rnd
_rnd lea rndseed,a0 ;Get address of seed
move.w 4(sp),d1 ;Get range argument
tst.w d1
ble.s setseed ;Go reset seed
move.l (a0),d0 ;Get seed
ADD.L D0,D0
BHI.S over
EORI.L #$1D872B41,D0
over
move.l d0,(a0) ;Save new seed
andi.l #$ffff,d0 ;Coerce into word
divu d1,d0 ;Divide by range
swap d0 ; and get remainder (modulus)
rts
setseed neg.w d1 ;Probably don't need this
move.l d1,(a0)
rts
dseg
rndseed dc.l 0
cseg
#endasm